// package: rewords-server-2024
// filename: cmgox
// author: diogoxiang@gmail.com
// time: 2024/7/31 上午10:20

package cmgox

import (
	"context"
	"rewords-server-2024/internal/library/cfg"

	"github.com/gogf/gf/v2/frame/g"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"

	"rewords-server-2024/internal/library/xpool"
	"time"
)

// Insert 插入
func Insert(ctx context.Context, table string, data interface{}, opts ...*options.InsertOneOptions) (err error) {
	var (
		collection *mongo.Collection
		_          *mongo.InsertOneResult
		client     *mongo.Client
		//mongoConf  *model.MongoConf
		// ctx context.Context
		p interface{}
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)

	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)
	client = p.(*mongo.Client)
	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	if _, err = collection.InsertOne(ctx, data, opts...); err != nil {
		g.Log().Warning(ctx, err)
		return
	}

	//g.Log().Info(ctx, "Insert ID:", result.InsertedID)
	return
}

// InsertMany 批量插入
func InsertMany(ctx context.Context, table string, data []interface{}, opts ...*options.InsertManyOptions) (err error) {

	var (
		collection *mongo.Collection
		result     *mongo.InsertManyResult
		client     *mongo.Client
		p          interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)

	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)

	client = p.(*mongo.Client)

	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	if result, err = collection.InsertMany(ctx, data, opts...); err != nil {
		g.Log().Warning(ctx, err)
		return
	}

	g.Log().Info(ctx, " 插入的 IDs：", result.InsertedIDs)

	return
}

// Find 查询所有all
func Find(ctx context.Context, table string, where, fields interface{}, page, pageSize int64, sort bson.D) (data []bson.M, err error) {
	var (
		collection  *mongo.Collection
		cursor      *mongo.Cursor
		findOptions *options.FindOptions
		client      *mongo.Client
		p           interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)
	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)

	client = p.(*mongo.Client)
	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	findOptions = options.Find()
	// 默认是按bsonx.id 提排序, 默认是倒序
	//findOptions.SetSort(bsonx.Doc{{"_id", bsonx.Int32(-1)}})
	if sort != nil {
		findOptions.SetSort(sort)
	} else {
		findOptions.SetSort(bson.D{{"_id", int32(-1)}})
	}

	// if page < 1 {
	// 	page = 1 // 确保 page 至少为 1
	// }
	if pageSize <= 0 {
		pageSize = 20 // 设置默认值
	}
	findOptions.SetSkip(page) // 传过的是游标 ,所以需要减一
	findOptions.SetLimit(pageSize)
	findOptions.SetProjection(fields)

	cursor, err = collection.Find(ctx, where, findOptions)
	if err != nil {
		return nil, err
	}

	defer cursor.Close(ctx)

	// 直接解码到 bson.M 切片
	if err = cursor.All(ctx, &data); err != nil {
		return nil, err
	}

	return data, nil

}

// FindOne 查询一个
func FindOne(ctx context.Context, table string, where, fields interface{}) (data bson.M, err error) {
	var (
		collection  *mongo.Collection
		res         *mongo.SingleResult
		findOptions *options.FindOneOptions
		client      *mongo.Client
		p           interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)
	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)

	client = p.(*mongo.Client)

	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	findOptions = options.FindOne()
	findOptions.SetProjection(fields)

	res = collection.FindOne(ctx, where, findOptions)

	data = bson.M{}
	if err = res.Decode(&data); err != nil {
		return nil, err
	}
	return
}

// FindAndModify 查询并修改,返回修改后的参数值
func FindAndModify(ctx context.Context, table string, where, update interface{}) (data interface{}, err error) {
	var (
		collection  *mongo.Collection
		res         *mongo.SingleResult
		findOptions *options.FindOneAndUpdateOptions
		client      *mongo.Client
		p           interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)
	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)

	client = p.(*mongo.Client)

	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	findOptions = options.FindOneAndUpdate()
	findOptions.SetUpsert(true)
	findOptions.SetReturnDocument(1)

	res = collection.FindOneAndUpdate(ctx, where, update, findOptions)

	//var oneRes interface{}
	if err = res.Decode(&data); err != nil {
		return nil, err
	}
	//data = &oneRes
	return

}

// UpdateOne 更新一个 可用于标记删除
func UpdateOne(ctx context.Context, table string, uptCond, update interface{}) (result *mongo.UpdateResult, err error) {
	var (
		collection *mongo.Collection
		client     *mongo.Client
		// opts       *options.UpdateOptions
		p interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)
	//log.Traceln("执行更新")
	opts := options.Update()
	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)

	client = p.(*mongo.Client)
	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	// 执行更新
	if result, err = collection.UpdateOne(ctx, uptCond, update, opts); err != nil {
		g.Log().Warning(ctx, err)
		return
	}

	return

}

// UpdateMany 更新一个 可用于标记删除
func UpdateMany(ctx context.Context, table string, uptCond, update interface{}) (result *mongo.UpdateResult, err error) {
	var (
		collection *mongo.Collection
		client     *mongo.Client
		// opts       *options.UpdateOptions
		p interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)

	//log.Traceln("执行更新")
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)
	opts := options.Update()

	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)

	client = p.(*mongo.Client)
	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	// 执行更新
	if result, err = collection.UpdateMany(ctx, uptCond, update, opts); err != nil {
		g.Log().Warning(ctx, err)
		return
	}

	return

}

// DelOne Real真实 慎用
func DelOne(ctx context.Context, table string, where interface{}) (err error) {
	var (
		collection *mongo.Collection
		client     *mongo.Client
		opts       *options.DeleteOptions
		p          interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)
	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)

	client = p.(*mongo.Client)
	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	// 执行删除
	if _, err = collection.DeleteOne(ctx, where, opts); err != nil {
		g.Log().Warning(ctx, err)
		return
	}
	return
}

// DelMany Real真实 慎用
func DelMany(ctx context.Context, table string, where interface{}) (err error) {
	var (
		collection *mongo.Collection
		client     *mongo.Client
		opts       *options.DeleteOptions
		p          interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)
	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)

	client = p.(*mongo.Client)
	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	// 执行删除
	if _, err = collection.DeleteMany(ctx, where, opts); err != nil {
		g.Log().Warning(ctx, err)
		return
	}
	return
}

// Count 统计类的数据
func Count(ctx context.Context, table string, where interface{}) (count int64, err error) {
	var (
		collection *mongo.Collection
		client     *mongo.Client
		//ctx        = context.Background()
		opts *options.CountOptions
		p    interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)
	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)
	// 设置最大超时是 20秒, 如果集合数再大就得另想办法了
	opts = options.Count()
	// FIXME: 这里配置参数
	opts.SetMaxTime(20 * time.Second)
	// 限制最大的文档, 后续要跟着索引进行相应的优化
	opts.SetLimit(1000)

	client = p.(*mongo.Client)
	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	if count, err = collection.CountDocuments(ctx, where, opts); err != nil {
		g.Log().Warning(ctx, "统计文档错误：", err)
		return
	}
	return
}

// EstimatedDocumentCount  统计
func EstimatedDocumentCount(ctx context.Context, table string, filter bson.D, opts ...*options.EstimatedDocumentCountOptions) (count int64, err error) {
	var (
		collection *mongo.Collection
		client     *mongo.Client
		//ctx        = context.Background()
		//opts       *options.CountOptions
		p interface{}

		//mongoConf *model.MongoConf
		// ctx context.Context
	)
	//mongoConf, err = service.SysConfig().GetMongoConfig(ctx)
	p, err = xpool.GMongoPool.Get()
	defer xpool.GMongoPool.Put(p)

	client = p.(*mongo.Client)
	collection = client.Database(cfg.GConfig.Mongo.DbName).Collection(table)

	if count, err = collection.EstimatedDocumentCount(ctx, opts...); err != nil {
		g.Log().Warning(ctx, "统计文档错误：", err)
		return
	}
	return
}
